package net.brucecooper.mindmap.client;

import gwt.canvas.client.Canvas;

import java.util.List;

import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

public class NodeTextWidget extends HorizontalPanel {
    LabelComponent nodeText = new LabelComponent();
    private NodeOutlineStyle outline;
	protected NodeWidget nodeWidget;
    private String foreground;
    private String background;
    
    public NodeTextWidget(NodeWidget nodeWidget) {
    	this.nodeWidget = nodeWidget;
        NodeDataStore dataStore = nodeWidget.getDataStore();
        int nodeID = nodeWidget.getNodeID();
        String icon = dataStore.getNodeIcon(nodeID);
        foreground = '#' + dataStore.getNodeForeground(nodeID);
        background = '#' + dataStore.getNodeBackground(nodeID);
        outline = dataStore.getNodeOutline(nodeID);
        
        
        if (outline == NodeOutlineStyle.CIRCLE) {
        	add(new Spacer(5));
        }
        
        if (icon != null) {
            add(new ImageComponent(icon + ".png"));
        }

        nodeText.setWordWrap(false);
        nodeText.setText(dataStore.getNodeName(nodeID));
        nodeText.setColor(foreground);
        switch (nodeWidget.getLevel()) {
            case 0:
                nodeText.setFontSize(20);
                break;
            case 1:
                nodeText.setFontSize(16);
                break;
            case 2:
                nodeText.setFontSize(12);
                nodeText.setPreferredHeight(12);
                break;
            default:
                nodeText.setFontSize(9);
                nodeText.setPreferredHeight(9);
                break;
        }
        add(nodeText);

        
        
        List<String> votesUp = dataStore.getVotesUp(nodeID); 
        List<String> votesDown = dataStore.getVotesDown(nodeID);
        boolean showUp = votesUp != null && votesUp.size() > 0;
        boolean showDown = votesDown != null && votesDown.size() > 0;
        if (showUp || showDown) {
            GraphicComponent header = new VerticalPanel(Panel.Alignment.LEFT) {
                @Override
            	public Widget getTooltip() {
            		return createVotesPanel();
            	}
            };
            header.setTooltipEnabled(true);
            if (showUp) {
            	header.add(createImgWithTxt("vote_yes_small.png", votesUp.size()));
            }
            if (showDown) {
            	header.add(createImgWithTxt("vote_no_small.png", votesDown.size()));
            }
            
            add(header);
        }
        if (outline == NodeOutlineStyle.CIRCLE) {
        	add(new Spacer(5));
        }
    }
    
    
    public int getBaseline(Canvas canvas) {
        return nodeText.getPreferredHeight(canvas);
    }
    
    @Override
    public int getPreferredHeight(Canvas canvas) {
    	int h = super.getPreferredHeight(canvas);
    	
    	if (outline == NodeOutlineStyle.CIRCLE || outline == NodeOutlineStyle.CLOUD) {
    		int w = getPreferredWidth(canvas);
    		h = Math.max(h, (int)(Math.log(w)/Math.log(2)*h/3.0));
    	}
    	return h;
    }
    

    
    private GraphicComponent createImgWithTxt(String icon, int size) {
    	GraphicComponent result = new HorizontalPanel();
    	result.add(new ImageComponent(icon));
    	LabelComponent lcomp =new LabelComponent(Integer.toString(size)); 
    	lcomp.setFontSize(9);
    	lcomp.setPreferredHeight(9);
    	result.add(lcomp);		
    	return result;
	}


    @Override
    public void paint(Canvas canvas, Clip clip) {
    	if (nodeWidget.isDropProhibited()) {
    		canvas.setGlobalAlpha(0.15);
    	}

    	
    	if (nodeWidget.isSelected()) {
            canvas.setFillStyle("darkGray");
            switch (outline) {
            case CIRCLE:
    			canvas.beginPath();
    			drawEllipse(canvas);
    	    	canvas.fill();
    	    	break;
            case CLOUD:
    			canvas.beginPath();
    			drawCloud(canvas);
    	    	canvas.fill();
    	    	break;
            case UNDERLINE:
                canvas.fillRect(0,0, getWidth(), getHeight());
                break;
            }
        }
        super.paint(canvas, clip);
    }
    
    private void drawCloud(Canvas g) {
		double rx = getWidth()/2.0;
		double ry = getHeight()/2.0;

		int numsteps = 12;
		double step = 2*Math.PI/numsteps;
		
		boolean first = true;
		double theta = 0.0;
		for (int i = 0; i <= numsteps; i++, theta += step) {
			double x = rx + rx * Math.cos(theta);
			double y = ry + ry * Math.sin(theta);
			
			if (first) {
				first = false;
				g.moveTo(x,y);
			} else {
				double cpx = rx + (rx+(ry*0.5)) * Math.cos(theta-step/2.0);
				double cpy = ry + (ry+(ry*0.5)) * Math.sin(theta-step/2.0);
				g.quadraticCurveTo(cpx, cpy, x, y);
			}
		}
    }

    private void drawEllipse(Canvas g) {
		int w = getWidth();
		int h = getHeight();
		g.moveTo(0, h/2);
		g.quadraticCurveTo(0,0, w/2, 0);
		g.quadraticCurveTo(w,0, w, h/2);
		g.quadraticCurveTo(w,h, w/2, h);
		g.quadraticCurveTo(0,h, 0, h/2);
    	
    }

    
	@Override
    public void paintComponent(Canvas g, Clip clip) {
    	String color = foreground;
    	
    	if (nodeWidget.isDropProhibited()) {
    		color = "lightGray";
    	} else if (nodeWidget.isDropTarget()) {
    		color = "red";
    		g.setLineWidth(4.0);
    	} else {
    		switch (outline) {
    		case CIRCLE:
        		color = foreground;
    			break;
    		case CLOUD:
        		color = foreground;
    			break;
    		case UNDERLINE:
        		color = "darkGreen";
    		}
    	}
		g.setStrokeStyle(color);
    	
		g.beginPath();
		switch (outline) {
		case CIRCLE:
			drawEllipse(g);
			break;
		case CLOUD:
			drawCloud(g);
			break;
		case UNDERLINE:
	    	g.moveTo(0,getHeight());
	    	g.lineTo(getWidth(), getHeight());
		}
    	g.stroke();
    }
    
    Grid createVotesPanel() {
    	NodeDataStore dataStore = nodeWidget.getDataStore();
        int nodeID = nodeWidget.getNodeID();
        List<String> votesUp = dataStore.getVotesUp(nodeID); 
        List<String> votesDown = dataStore.getVotesDown(nodeID);
        Grid list = new Grid(Math.max(votesUp == null ? 0 : votesUp.size(), votesDown == null ? 0 : votesDown.size()) + 1, 2);
        list.setCellSpacing(0);
        list.setCellPadding(0);
        list.addStyleName("votesgrid");
        
        list.setWidget(0, 0, new HTML(IconManager.makeImgHTML("Voted Up",  "vote_yes.png") + "Votes For"));
        list.setWidget(0, 1, new HTML(IconManager.makeImgHTML("Voted Down",  "vote_no.png") + "Votes Against"));
        
        int count = 1;
        if (votesUp != null ) {
            for (String name: votesUp) {
                Label l = new Label(name);
                l.addStyleName("voteyes");
                list.setWidget(count++, 0, l);
            }
        }
        count = 1;
        if (votesDown != null) {
            for (String name: votesDown) {
                Label l = new Label(name);
                l.addStyleName("voteno");
                list.setWidget(count++, 1, l);
            }
        }
        return list;

    }
    public String getText() {
        return nodeText.getText();
    }
    public void setText(String newName) {
        nodeText.setText(newName);
    }

    public NodeWidget getNodeWidget() {
    	return nodeWidget;
	}
}
